use std::collections::HashMap;
use std::sync::Arc;

use actix_web::{HttpRequest, web};

use common::ctx::{Dict, set_dict_conf};
use common::error::MyError;
use common::header::Authorization;
use entity::{sys_dict, sys_dict_group};
use model::dict::{CreateDict, CreateDictGroup, DictGroupPage, DictPage};

use crate::base::BaseService;
use crate::manager::base::BaseManager;
use crate::manager::dict::DictManager;
use crate::manager::dict_group::DictGroupManager;

pub struct DictGroupService {}

impl
    BaseService<
        i64,
        sys_dict_group::Model,
        DictGroupPage,
        CreateDictGroup,
        sys_dict_group::Model,
        DictGroupManager,
    > for DictGroupService
{
    async fn add(
        form: CreateDictGroup,
        _req: &HttpRequest,
        _authorization: web::Header<Authorization>,
    ) -> Result<i64, MyError> {
        let res = DictGroupManager::add(form).await?;
        let conf = DictGroupService::init_dict_conf().await?;
        set_dict_conf(Option::from(conf))?;
        Ok(res)
    }

    async fn delete(
        id: i64,
        _req: &HttpRequest,
        _authorization: web::Header<Authorization>,
    ) -> Result<bool, MyError> {
        let res = DictGroupManager::delete(id).await?;
        let conf = DictGroupService::init_dict_conf().await?;
        set_dict_conf(Option::from(conf))?;
        Ok(res)
    }
}

impl DictGroupService {
    pub async fn search_list(page: DictGroupPage) -> Result<Vec<sys_dict_group::Model>, MyError> {
        Ok(DictGroupManager::search_list(page).await?)
    }
    pub async fn init_dict_conf() -> Result<HashMap<String, Arc<(Vec<Dict>, Vec<Dict>)>>, MyError> {
        let mut dict_conf = HashMap::default();
        let group_list = DictGroupManager::list().await?;
        for group in group_list {
            let dict_list = DictManager::get_by_group_id(group.id).await?;
            let dict_tree = build_dict_tree(&dict_list)?;
            let mut list = Vec::new();
            for dict in dict_list {
                list.push(Dict {
                    id: dict.id,
                    name: dict.name.unwrap(),
                    code: dict.code.unwrap(),
                    value: dict.value.unwrap(),
                    children: None,
                })
            }
            dict_conf.insert(group.group_code.unwrap(), Arc::new((list, dict_tree)));
        }
        Ok(dict_conf)
    }
}

fn build_dict_tree(dict_list: &Vec<sys_dict::Model>) -> Result<Vec<Dict>, MyError> {
    let mut dict_tree = Vec::new();
    let res = get_root_dict(dict_list)?;
    let root_dict = res.0;
    let child_dict_map = res.1;
    for dict in root_dict {
        let mut children = vec![];
        if child_dict_map.contains_key(&dict.id) {
            children = build_child_dict(&child_dict_map, &dict.id)?;
        }
        dict_tree.push(Dict {
            id: dict.id,
            name: dict.name.unwrap(),
            code: dict.code.unwrap(),
            value: dict.value.unwrap(),
            children: Some(children),
        })
    }
    Ok(dict_tree)
}

fn get_root_dict(
    dict_list: &Vec<sys_dict::Model>,
) -> Result<(Vec<sys_dict::Model>, HashMap<i64, Vec<sys_dict::Model>>), MyError> {
    let mut root_dict = Vec::new();
    let mut child_dict_map = HashMap::default();
    for dict in dict_list {
        if dict.parent_id.is_some() && dict.parent_id.unwrap() == 0 {
            root_dict.push(dict.clone());
        } else {
            child_dict_map
                .entry(dict.parent_id.unwrap())
                .or_insert(vec![])
                .push(dict.clone());
        }
    }
    Ok((root_dict, child_dict_map))
}

fn build_child_dict(
    all_dict_map: &HashMap<i64, Vec<sys_dict::Model>>,
    parent_id: &i64,
) -> Result<Vec<Dict>, MyError> {
    let mut reuslt = vec![];
    let child_vec = all_dict_map.get(parent_id);
    match child_vec {
        None => {}
        Some(child_vec) => {
            for c in child_vec {
                let mut children = vec![];
                if all_dict_map.contains_key(&c.id) {
                    children = build_child_dict(all_dict_map, &c.id)?;
                }
                reuslt.push(Dict {
                    id: c.id,
                    name: c.name.clone().unwrap(),
                    code: c.code.clone().unwrap(),
                    value: c.value.clone().unwrap(),
                    children: Some(children),
                })
            }
        }
    }
    Ok(reuslt)
}

pub struct DictService {}

impl BaseService<i64, sys_dict::Model, DictPage, CreateDict, sys_dict::Model, DictManager>
    for DictService
{
    async fn add(
        form: CreateDict,
        _req: &HttpRequest,
        _authorization: web::Header<Authorization>,
    ) -> Result<i64, MyError> {
        let res = DictManager::add(form).await?;
        let conf = DictGroupService::init_dict_conf().await?;
        set_dict_conf(Option::from(conf))?;
        Ok(res)
    }

    async fn update(
        form: sys_dict::Model,
        _req: &HttpRequest,
        _authorization: web::Header<Authorization>,
    ) -> Result<i64, MyError> {
        let res = DictManager::update(form).await?;
        let conf = DictGroupService::init_dict_conf().await?;
        set_dict_conf(Option::from(conf))?;
        Ok(res)
    }

    async fn delete(
        id: i64,
        _req: &HttpRequest,
        _authorization: web::Header<Authorization>,
    ) -> Result<bool, MyError> {
        let res = DictManager::delete(id).await?;
        let conf = DictGroupService::init_dict_conf().await?;
        set_dict_conf(Option::from(conf))?;
        Ok(res)
    }
}
